﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using DimensionsHelper.Common.Contracts.Excel;
using DimensionsHelper.Common.Contracts.Excel.Options;
using DimensionsHelper.Common.TableFormatter;
using OfficeOpenXml;

namespace DimensionsHelper.Services.Excel.EPPlus;

public class ExcelWorkbookOperator : IExcelWorkbookOperator
{

    private bool _disposed;
    private string? _fullName;
    private ExcelPackage? _package;
    private ExcelWorkbook? _workbook;
    private Dictionary<string, ExcelWorksheetOperator>? _worksheets;

    static ExcelWorkbookOperator()
    {
        ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
    }


    public bool IsInitialized { get; private set; }


    public string FileName
    {
        get
        {
            if (_package?.File != null)
            {
                return _package.File.FullName;
            }

            return _fullName ?? string.Empty;
        }
    }


    public FontStyleOptions HyperlinkStyleOptions { get; set; } = 
        TableFormatterDefaultValues.DefaultHyperlinkStyleOptions;

    public FontStyleOptions GlobalFontStyleOptions { get; set; } = new FontStyleOptions();

    private void CheckInitialized()
    {
        if (!IsInitialized)
        {
            throw new Exception($"Excel尚未初始化，请先调用'{nameof(IExcelWorkbookOperator.Open)}'或'{nameof(IExcelWorkbookOperator.Create)}'方法创建或打开文件。");
        }
    }

    private void CheckDisposed()
    {
        if (_disposed)
        {
            throw new Exception("Excel对象已关闭，无法使用此对象打开或创建文件。");
        }

        _package?.Dispose();
    }

    public void Open(string fileName)
    {
        CheckDisposed();

        if (!File.Exists(fileName))
        {
            throw new Exception($"{fileName} 不存在.");
        }

        _fullName = fileName;
        _package = new ExcelPackage(new FileInfo(fileName));
        _workbook = _package.Workbook;

        IsInitialized = true;
    }

    public void Create(string fileName)
    {
        CheckDisposed();

        if (string.IsNullOrEmpty(fileName))
        {
            throw new IOException("文件路径无效");
        }

        if (File.Exists(fileName))
        {
            File.Delete(fileName);
        }

        _fullName = fileName;
        _package = new ExcelPackage(new FileInfo(fileName));
        _workbook = _package.Workbook;

        IsInitialized = true;
    }

    private void InitWorksheets()
    {
        if (_worksheets != null)
        {
            return;
        }
        
        _worksheets = new Dictionary<string, ExcelWorksheetOperator>(StringComparer.OrdinalIgnoreCase);

        foreach (var sheet in _workbook!.Worksheets)
        {
            _worksheets.Add(sheet.Name, ExcelWorksheetOperator.Create(this, sheet));
        }
    }
    

    public IList<IExcelWorksheetOperator> Worksheets
    {
        get
        {
            CheckInitialized();
            InitWorksheets();
            return _worksheets!.Values.ToList<IExcelWorksheetOperator>();
        }
    }

    public void DeleteWorksheet(string sheetName)
    {
        CheckInitialized();
        InitWorksheets();
        if (_worksheets!.Remove(sheetName))
        {
            _workbook!.Worksheets.Delete(sheetName);
        }
    }


    public bool ContainsWorksheet(string sheetName)
    {
        CheckInitialized();
        InitWorksheets();
        return _worksheets!.ContainsKey(sheetName);
    }


    public IExcelWorksheetOperator GetWorksheet(string sheetName)
    {
        CheckInitialized();
        InitWorksheets();

        if (_worksheets!.TryGetValue(sheetName, out var worksheetOperator))
        {
            return worksheetOperator;
        }
        
        var sheet = _workbook!.Worksheets.Add(sheetName); 
        var sheetOperator = ExcelWorksheetOperator.Create(this, sheet);
        _worksheets.Add(sheetName, sheetOperator);
        return sheetOperator;
    }

    public void Close(bool withoutSave = true)
    {
        if (_disposed || !IsInitialized)
        {
            return;
        }

        if (!withoutSave)
        {
            _package!.Save();
        }

        _package!.Dispose();
        _disposed = true;
    }

    public void Save(string destination = "")
    {
        CheckInitialized();

        if (string.IsNullOrEmpty(destination))
        {
            _package!.Save();
        }
        else
        {
            _package!.SaveAs(destination);
        }
    }

}